/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.alertnetusa.validator;

import java.io.*;
import java.util.*;
import java.net.URL;
import com.incident.cap.*;
import javax.xml.validation.*;
import javax.xml.transform.stream.StreamSource;
import org.xml.sax.SAXException;

import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;

//import javax.xml.parsers.*;
//import org.w3c.dom.*;
//import org.xml.sax.*;
/** 
 * EASCAPValidator - Make sure EAS-CAP adheres to EAS-CAP format.
 * <i>Copyright (c) 2008-2009 Thai Van<p>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 * @see EasCapAlert
 * @author Thai Van, Prafash Kumar
 * @version 1 Oct 2008
 * 
 */
public class EasCapValidator {

    /** Static value for all valid CAP */
    protected final static String VALID = "VALID";
    /** EAS-CAP parsed out of CAP */
    protected EasCapAlert _easCapAlert = null;
    /** EASCAP Info extracted from EAS-CAP */
    protected EasCapInfo _easCapInfo = null;
    /** EASCAP Area extracted from EAS-CAP */
    protected EasCapArea _easCapArea = null;
    /** result after validation procedure */
    protected String resultState = null;
    private String _xmlns = "\"urn:oasis:names:tc:emergency:cap:1.1\":";

    public EasCapValidator() {
    }

    /**
     * 1. Take a CAP message. Parse EAS-CAP out of CAP message. 
     * 2. Then validate that EAS-CAP message against an EAS-CAP schema to make sure that it is conformed 
     * to EAS-CAP format and that it has the minimum set of EAS-CAP required elements.
     * 3. Then make sure all EAS-CAP required elements are valid   
     *
     * @param  cap  a CAP XML String
     * @return                  a result of whether Accepted, Rejected, or Ignored. Validation informations will be returned along with result in the format of "Rejected: ..."
     */
    public String validateEASCAP(String cap) throws Exception {
        return validate(cap, null, readTextFileFromJar("eascap.xsd"));
    }

    /**
     * 1. Take a CAP message. Parse EAS-CAP out of CAP message. 
     * 2. Then validate that EAS-CAP message against an EAS-CAP schema to make sure that it is conformed 
     * to EAS-CAP format and that it has the minimum set of EAS-CAP required elements.
     * 3. Then make sure all EAS-CAP required elements are valid   
     *
     * @param  cap          a CAP XML String
     * @param  easCapXsd    an EAS-CAP Schema String
     * @return                  a result of whether Accepted, Rejected, or Ignored. Validation informations will be returned along with result in the format of "Rejected: ..."
     */
    public String validateEASCAP(String cap, String easCapXsd) throws Exception {
        return validate(cap, null, easCapXsd);
    }

    /**
     * 1. Take a CAP message. Parse EAS-CAP out of CAP message. 
     * 2. Then validate that EAS-CAP message against an EAS-CAP schema to make sure that it is conformed 
     * to EAS-CAP format and that it has the minimum set of EAS-CAP required elements.
     * 3. Then make sure all EAS-CAP required elements are valid   
     *
     * @param  cap              a CAP XML String
     * @param  easCapXsdFile    an EAS-CAP Schema file
     * @return                  a result of whether Accepted, Rejected, or Ignored. Validation informations will be returned along with result in the format of "Rejected: ..."
     */
    public String validateEASCAP(String cap, File easCapXsdFile) throws Exception {
        return validate(cap, null, readTextFile(easCapXsdFile));
    }

    /**
     * 1. Take a CAP message. Parse EAS-CAP out of CAP message. 
     * 2. Then validate that EAS-CAP message against an EAS-CAP schema to make sure that it is conformed 
     * to EAS-CAP format and that it has the minimum set of EAS-CAP required elements.
     * 3. Then make sure all EAS-CAP required elements are valid   
     *
     * @param  cap              a CAP XML String
     * @param  easCapXsdUrl     an EAS-CAP Schema URL
     * @return                  a result of whether Accepted, Rejected, or Ignored. Validation informations will be returned along with result in the format of "Rejected: ..."
     */
    public String validateEASCAP(String cap, URL easCapXsdUrl) throws Exception {
        return validate(cap, null, readTextURL(easCapXsdUrl));
    }

    /**
     * 1. Take a CAP message. Parse EAS-CAP out of CAP message. 
     * 2. Then validate that EAS-CAP message against an EAS-CAP schema to make sure that it is conformed 
     * to EAS-CAP format and that it has the minimum set of EAS-CAP required elements.
     * 3. Then make sure all EAS-CAP required elements are valid   
     *
     * @param  capFile          a CAP XML file
     * @return                  a result of whether Accepted, Rejected, or Ignored. Validation informations will be returned along with result in the format of "Rejected: ..."
     */
    public String validateEASCAP(File capFile) throws Exception {
        return validate(readTextFile(capFile), null, readTextFileFromJar("eascap.xsd"));
    }

    /**
     * 1. Take a CAP message. Parse EAS-CAP out of CAP message. 
     * 2. Then validate that EAS-CAP message against an EAS-CAP schema to make sure that it is conformed 
     * to EAS-CAP format and that it has the minimum set of EAS-CAP required elements.
     * 3. Then make sure all EAS-CAP required elements are valid   
     *
     * @param  capFile          a CAP XML file
     * @param  easCapXsd        an EAS-CAP Schema String
     * @return                  a result of whether Accepted, Rejected, or Ignored. Validation informations will be returned along with result in the format of "Rejected: ..."
     */
    public String validateEASCAP(File capFile, String easCapXsd) throws Exception {
        return validate(readTextFile(capFile), null, easCapXsd);
    }

    /**
     * 1. Take a CAP message. Parse EAS-CAP out of CAP message. 
     * 2. Then validate that EAS-CAP message against an EAS-CAP schema to make sure that it is conformed 
     * to EAS-CAP format and that it has the minimum set of EAS-CAP required elements.
     * 3. Then make sure all EAS-CAP required elements are valid   
     *
     * @param  capFile          a CAP XML file
     * @param  easCapXsdFile    an EAS-CAP Schema file
     * @return                  a result of whether Accepted, Rejected, or Ignored. Validation informations will be returned along with result in the format of "Rejected: ..."
     */
    public String validateEASCAP(File capFile, File easCapXsdFile) throws Exception {
        return validate(readTextFile(capFile), null, readTextFile(easCapXsdFile));
    }

    /**
     * 1. Take a CAP message. Parse EAS-CAP out of CAP message. 
     * 2. Then validate that EAS-CAP message against an EAS-CAP schema to make sure that it is conformed 
     * to EAS-CAP format and that it has the minimum set of EAS-CAP required elements.
     * 3. Then make sure all EAS-CAP required elements are valid   
     *
     * @param  capFile          a CAP XML file
     * @param  easCapXsdUrl     an EAS-CAP Schema URL
     * @return                  a result of whether Accepted, Rejected, or Ignored. Validation informations will be returned along with result in the format of "Rejected: ..."
     */
    public String validateEASCAP(File capFile, URL easCapXsdUrl) throws Exception {
        return validate(readTextFile(capFile), null, readTextURL(easCapXsdUrl));
    }

    /**
     * 1. Take a CAP message. Validate it against a CAP 1.1 schema to make sure that it is conformed 
     * to CAP 1.1 format and that it has the minimum set of CAP 1.1 required elements.
     * 2. Parse EAS-CAP out of CAP message. 
     * 3. Then validate that EAS-CAP message against an EAS-CAP schema to make sure that it is conformed 
     * to EAS-CAP format and that it has the minimum set of EAS-CAP required elements.
     * 4. Then make sure all EAS-CAP required elements are valid   
     *
     * @param  cap              a CAP XML String
     * @return                  a result of whether Accepted, Rejected, or Ignored. Validation informations will be returned along with result in the format of "Rejected: ..."
     */
    public String validateEASCAPWithStrictCAPConformance(String cap) throws Exception {
        return validate(cap, readTextFileFromJar("cap.xsd"), readTextFileFromJar("eascap.xsd"));
    }

    /**
     * 1. Take a CAP message. Validate it against a CAP 1.1 schema to make sure that it is conformed 
     * to CAP 1.1 format and that it has the minimum set of CAP 1.1 required elements.
     * 2. Parse EAS-CAP out of CAP message. 
     * 3. Then validate that EAS-CAP message against an EAS-CAP schema to make sure that it is conformed 
     * to EAS-CAP format and that it has the minimum set of EAS-CAP required elements.
     * 4. Then make sure all EAS-CAP required elements are valid   
     *
     * @param  cap              a CAP XML String
     * @param  capXsd           a CAP Schema String
     * @param  easCapXsd        a EAS-CAP Schema String
     * @return                  a result of whether Accepted, Rejected, or Ignored. Validation informations will be returned along with result in the format of "Rejected: ..."
     */
    public String validateEASCAPWithStrictCAPConformance(String cap, String capXsd, String easCapXsd) throws Exception {
        return validate(cap, capXsd, easCapXsd);
    }

    /**
     * 1. Take a CAP message. Validate it against a CAP 1.1 schema to make sure that it is conformed 
     * to CAP 1.1 format and that it has the minimum set of CAP 1.1 required elements.
     * 2. Parse EAS-CAP out of CAP message. 
     * 3. Then validate that EAS-CAP message against an EAS-CAP schema to make sure that it is conformed 
     * to EAS-CAP format and that it has the minimum set of EAS-CAP required elements.
     * 4. Then make sure all EAS-CAP required elements are valid   
     *
     * @param  cap              a CAP XML String
     * @param  capXsd           a CAP Schema String
     * @param  easCapXsdFile    a EAS-CAP Schema file
     * @return                  a result of whether Accepted, Rejected, or Ignored. Validation informations will be returned along with result in the format of "Rejected: ..."
     */
    public String validateEASCAPWithStrictCAPConformance(String cap, String capXsd, File easCapXsdFile) throws Exception {
        return validate(cap, capXsd, readTextFile(easCapXsdFile));
    }

    /**
     * 1. Take a CAP message. Validate it against a CAP 1.1 schema to make sure that it is conformed 
     * to CAP 1.1 format and that it has the minimum set of CAP 1.1 required elements.
     * 2. Parse EAS-CAP out of CAP message. 
     * 3. Then validate that EAS-CAP message against an EAS-CAP schema to make sure that it is conformed 
     * to EAS-CAP format and that it has the minimum set of EAS-CAP required elements.
     * 4. Then make sure all EAS-CAP required elements are valid   
     *
     * @param  cap              a CAP XML String
     * @param  capXsd           a CAP Schema String
     * @param  easCapXsdUrl     a EAS-CAP Schema URL
     * @return                  a result of whether Accepted, Rejected, or Ignored. Validation informations will be returned along with result in the format of "Rejected: ..."
     */
    public String validateEASCAPWithStrictCAPConformance(String cap, String capXsd, URL easCapUrl) throws Exception {
        return validate(cap, capXsd, readTextURL(easCapUrl));
    }

    /**
     * 1. Take a CAP message. Validate it against a CAP 1.1 schema to make sure that it is conformed 
     * to CAP 1.1 format and that it has the minimum set of CAP 1.1 required elements.
     * 2. Parse EAS-CAP out of CAP message. 
     * 3. Then validate that EAS-CAP message against an EAS-CAP schema to make sure that it is conformed 
     * to EAS-CAP format and that it has the minimum set of EAS-CAP required elements.
     * 4. Then make sure all EAS-CAP required elements are valid   
     *
     * @param  cap              a CAP XML String
     * @param  capXsdFile       a CAP Schema File
     * @param  easCapXsd        a EAS-CAP Schema String
     * @return                  a result of whether Accepted, Rejected, or Ignored. Validation informations will be returned along with result in the format of "Rejected: ..."
     */
    public String validateEASCAPWithStrictCAPConformance(String cap, File capXsdFile, String easCapXsd) throws Exception {
        return validate(cap, readTextFile(capXsdFile), easCapXsd);
    }

    /**
     * 1. Take a CAP message. Validate it against a CAP 1.1 schema to make sure that it is conformed 
     * to CAP 1.1 format and that it has the minimum set of CAP 1.1 required elements.
     * 2. Parse EAS-CAP out of CAP message. 
     * 3. Then validate that EAS-CAP message against an EAS-CAP schema to make sure that it is conformed 
     * to EAS-CAP format and that it has the minimum set of EAS-CAP required elements.
     * 4. Then make sure all EAS-CAP required elements are valid   
     *
     * @param  cap              a CAP XML String
     * @param  capXsdFile       a CAP Schema File
     * @param  easCapXsdFile    a EAS-CAP Schema File
     * @return                  a result of whether Accepted, Rejected, or Ignored. Validation informations will be returned along with result in the format of "Rejected: ..."
     */
    public String validateEASCAPWithStrictCAPConformance(String cap, File capXsdFile, File easCapXsdFile) throws Exception {
        return validate(cap, readTextFile(capXsdFile), readTextFile(easCapXsdFile));
    }

    /**
     * 1. Take a CAP message. Validate it against a CAP 1.1 schema to make sure that it is conformed 
     * to CAP 1.1 format and that it has the minimum set of CAP 1.1 required elements.
     * 2. Parse EAS-CAP out of CAP message. 
     * 3. Then validate that EAS-CAP message against an EAS-CAP schema to make sure that it is conformed 
     * to EAS-CAP format and that it has the minimum set of EAS-CAP required elements.
     * 4. Then make sure all EAS-CAP required elements are valid   
     *
     * @param  cap              a CAP XML String
     * @param  capXsdFile       a CAP Schema File
     * @param  easCapXsdUrl     a EAS-CAP Schema URL
     * @return                  a result of whether Accepted, Rejected, or Ignored. Validation informations will be returned along with result in the format of "Rejected: ..."
     */
    public String validateEASCAPWithStrictCAPConformance(String cap, File capXsdFile, URL easCapXsdUrl) throws Exception {
        return validate(cap, readTextFile(capXsdFile), readTextURL(easCapXsdUrl));
    }

    /**
     * 1. Take a CAP message. Validate it against a CAP 1.1 schema to make sure that it is conformed 
     * to CAP 1.1 format and that it has the minimum set of CAP 1.1 required elements.
     * 2. Parse EAS-CAP out of CAP message. 
     * 3. Then validate that EAS-CAP message against an EAS-CAP schema to make sure that it is conformed 
     * to EAS-CAP format and that it has the minimum set of EAS-CAP required elements.
     * 4. Then make sure all EAS-CAP required elements are valid   
     *
     * @param  cap              a CAP XML String
     * @param  capXsdUrl        a CAP Schema URL
     * @param  easCapXsd        a EAS-CAP Schema String
     * @return                  a result of whether Accepted, Rejected, or Ignored. Validation informations will be returned along with result in the format of "Rejected: ..."
     */
    public String validateEASCAPWithStrictCAPConformance(String cap, URL capXsdUrl, String easCapXsd) throws Exception {
        return validate(cap, readTextURL(capXsdUrl), easCapXsd);
    }

    /**
     * 1. Take a CAP message. Validate it against a CAP 1.1 schema to make sure that it is conformed 
     * to CAP 1.1 format and that it has the minimum set of CAP 1.1 required elements.
     * 2. Parse EAS-CAP out of CAP message. 
     * 3. Then validate that EAS-CAP message against an EAS-CAP schema to make sure that it is conformed 
     * to EAS-CAP format and that it has the minimum set of EAS-CAP required elements.
     * 4. Then make sure all EAS-CAP required elements are valid   
     *
     * @param  cap              a CAP XML String
     * @param  capXsdUrl        a CAP Schema URL
     * @param  easCapXsdFile    a EAS-CAP Schema file
     * @return                  a result of whether Accepted, Rejected, or Ignored. Validation informations will be returned along with result in the format of "Rejected: ..."
     */
    public String validateEASCAPWithStrictCAPConformance(String cap, URL capXsdUrl, File easCapXsdFile) throws Exception {
        return validate(cap, readTextURL(capXsdUrl), readTextFile(easCapXsdFile));
    }

    /**
     * 1. Take a CAP message. Validate it against a CAP 1.1 schema to make sure that it is conformed 
     * to CAP 1.1 format and that it has the minimum set of CAP 1.1 required elements.
     * 2. Parse EAS-CAP out of CAP message. 
     * 3. Then validate that EAS-CAP message against an EAS-CAP schema to make sure that it is conformed 
     * to EAS-CAP format and that it has the minimum set of EAS-CAP required elements.
     * 4. Then make sure all EAS-CAP required elements are valid   
     *
     * @param  cap              a CAP XML String
     * @param  capXsdUrl        a CAP Schema URL
     * @param  easCapXsdFile    a EAS-CAP Schema file
     * @return                  a result of whether Accepted, Rejected, or Ignored. Validation informations will be returned along with result in the format of "Rejected: ..."
     */
    public String validateEASCAPWithStrictCAPConformance(String eascap, URL capxsdurl, URL eascapxsdurl) throws Exception {
        return validate(eascap, readTextURL(capxsdurl), readTextURL(eascapxsdurl));
    }

    /**
     * 1. Take a CAP message. Validate it against a CAP 1.1 schema to make sure that it is conformed 
     * to CAP 1.1 format and that it has the minimum set of CAP 1.1 required elements.
     * 2. Parse EAS-CAP out of CAP message. 
     * 3. Then validate that EAS-CAP message against an EAS-CAP schema to make sure that it is conformed 
     * to EAS-CAP format and that it has the minimum set of EAS-CAP required elements.
     * 4. Then make sure all EAS-CAP required elements are valid   
     *
     * @param  capFile          a CAP XML file
     * @return                  a result of whether Accepted, Rejected, or Ignored. Validation informations will be returned along with result in the format of "Rejected: ..."
     */
    public String validateEASCAPWithStrictCAPConformance(File capfile) throws Exception {
        return validate(readTextFile(capfile), readTextFile(new File("cap.xsd")), readTextFile(new File("eascap.xsd")));
    }

    /**
     * 1. Take a CAP message. Validate it against a CAP 1.1 schema to make sure that it is conformed 
     * to CAP 1.1 format and that it has the minimum set of CAP 1.1 required elements.
     * 2. Parse EAS-CAP out of CAP message. 
     * 3. Then validate that EAS-CAP message against an EAS-CAP schema to make sure that it is conformed 
     * to EAS-CAP format and that it has the minimum set of EAS-CAP required elements.
     * 4. Then make sure all EAS-CAP required elements are valid   
     *
     * @param  capFile          a CAP XML file
     * @param  capXsd           a CAP Schema String
     * @param  easCapXsd        a EAS-CAP Schema String
     * @return                  a result of whether Accepted, Rejected, or Ignored. Validation informations will be returned along with result in the format of "Rejected: ..."
     */
    public String validateEASCAPWithStrictCAPConformance(File capFile, String capXsd, String easCapXsd) throws Exception {
        return validate(readTextFile(capFile), capXsd, easCapXsd);
    }

    /**
     * 1. Take a CAP message. Validate it against a CAP 1.1 schema to make sure that it is conformed 
     * to CAP 1.1 format and that it has the minimum set of CAP 1.1 required elements.
     * 2. Parse EAS-CAP out of CAP message. 
     * 3. Then validate that EAS-CAP message against an EAS-CAP schema to make sure that it is conformed 
     * to EAS-CAP format and that it has the minimum set of EAS-CAP required elements.
     * 4. Then make sure all EAS-CAP required elements are valid   
     *
     * @param  capFile          a CAP XML file
     * @param  capXsd           a CAP Schema String
     * @param  easCapXsdFile    a EAS-CAP Schema file
     * @return                  a result of whether Accepted, Rejected, or Ignored. Validation informations will be returned along with result in the format of "Rejected: ..."
     */
    public String validateEASCAPWithStrictCAPConformance(File capFile, String capXsd, File easCapXsdFile) throws Exception {
        return validate(readTextFile(capFile), capXsd, readTextFile(easCapXsdFile));
    }

    /**
     * 1. Take a CAP message. Validate it against a CAP 1.1 schema to make sure that it is conformed 
     * to CAP 1.1 format and that it has the minimum set of CAP 1.1 required elements.
     * 2. Parse EAS-CAP out of CAP message. 
     * 3. Then validate that EAS-CAP message against an EAS-CAP schema to make sure that it is conformed 
     * to EAS-CAP format and that it has the minimum set of EAS-CAP required elements.
     * 4. Then make sure all EAS-CAP required elements are valid   
     *
     * @param  capFile          a CAP XML file
     * @param  capXsd           a CAP Schema String
     * @param  easCapXsdUrl     a EAS-CAP Schema URL
     * @return                  a result of whether Accepted, Rejected, or Ignored. Validation informations will be returned along with result in the format of "Rejected: ..."
     */
    public String validateEASCAPWithStrictCAPConformance(File capFile, String capXsd, URL easCapUrl) throws Exception {
        return validate(readTextFile(capFile), capXsd, readTextURL(easCapUrl));
    }

    /**
     * 1. Take a CAP message. Validate it against a CAP 1.1 schema to make sure that it is conformed 
     * to CAP 1.1 format and that it has the minimum set of CAP 1.1 required elements.
     * 2. Parse EAS-CAP out of CAP message. 
     * 3. Then validate that EAS-CAP message against an EAS-CAP schema to make sure that it is conformed 
     * to EAS-CAP format and that it has the minimum set of EAS-CAP required elements.
     * 4. Then make sure all EAS-CAP required elements are valid   
     *
     * @param  capFile          a CAP XML file
     * @param  capXsdFile       a CAP Schema file
     * @param  easCapXsd        a EAS-CAP Schema String
     * @return                  a result of whether Accepted, Rejected, or Ignored. Validation informations will be returned along with result in the format of "Rejected: ..."
     */
    public String validateEASCAPWithStrictCAPConformance(File capFile, File capXsdFile, String easCapXsd) throws Exception {
        return validate(readTextFile(capFile), readTextFile(capXsdFile), easCapXsd);
    }

    /**
     * 1. Take a CAP message. Validate it against a CAP 1.1 schema to make sure that it is conformed 
     * to CAP 1.1 format and that it has the minimum set of CAP 1.1 required elements.
     * 2. Parse EAS-CAP out of CAP message. 
     * 3. Then validate that EAS-CAP message against an EAS-CAP schema to make sure that it is conformed 
     * to EAS-CAP format and that it has the minimum set of EAS-CAP required elements.
     * 4. Then make sure all EAS-CAP required elements are valid   
     *
     * @param  capFile          a CAP XML file
     * @param  capXsdFile       a CAP Schema file
     * @param  easCapXsdFile    a EAS-CAP Schema file
     * @return                  a result of whether Accepted, Rejected, or Ignored. Validation informations will be returned along with result in the format of "Rejected: ..."
     */
    public String validateEASCAPWithStrictCAPConformance(File capFile, File capXsdFile, File easCapXsdFile) throws Exception {
        return validate(readTextFile(capFile), readTextFile(capXsdFile), readTextFile(easCapXsdFile));
    }

    /**
     * 1. Take a CAP message. Validate it against a CAP 1.1 schema to make sure that it is conformed 
     * to CAP 1.1 format and that it has the minimum set of CAP 1.1 required elements.
     * 2. Parse EAS-CAP out of CAP message. 
     * 3. Then validate that EAS-CAP message against an EAS-CAP schema to make sure that it is conformed 
     * to EAS-CAP format and that it has the minimum set of EAS-CAP required elements.
     * 4. Then make sure all EAS-CAP required elements are valid   
     *
     * @param  capFile          a CAP XML file
     * @param  capXsdFile       a CAP Schema file
     * @param  easCapXsdUrl     a EAS-CAP Schema URL
     * @return                  a result of whether Accepted, Rejected, or Ignored. Validation informations will be returned along with result in the format of "Rejected: ..."
     */
    public String validateEASCAPWithStrictCAPConformance(File capFile, File capXsdFile, URL easCapXsdUrl) throws Exception {
        return validate(readTextFile(capFile), readTextFile(capXsdFile), readTextURL(easCapXsdUrl));
    }

    /**
     * 1. Take a CAP message. Validate it against a CAP 1.1 schema to make sure that it is conformed 
     * to CAP 1.1 format and that it has the minimum set of CAP 1.1 required elements.
     * 2. Parse EAS-CAP out of CAP message. 
     * 3. Then validate that EAS-CAP message against an EAS-CAP schema to make sure that it is conformed 
     * to EAS-CAP format and that it has the minimum set of EAS-CAP required elements.
     * 4. Then make sure all EAS-CAP required elements are valid   
     *
     * @param  capFile          a CAP XML file
     * @param  capXsdUrl        a CAP Schema URL
     * @param  easCapXsd        a EAS-CAP Schema String
     * @return                  a result of whether Accepted, Rejected, or Ignored. Validation informations will be returned along with result in the format of "Rejected: ..."
     */
    public String validateEASCAPWithStrictCAPConformance(File capFile, URL capXsdUrl, String easCapXsd) throws Exception {
        return validate(readTextFile(capFile), readTextURL(capXsdUrl), easCapXsd);
    }

    /**
     * 1. Take a CAP message. Validate it against a CAP 1.1 schema to make sure that it is conformed 
     * to CAP 1.1 format and that it has the minimum set of CAP 1.1 required elements.
     * 2. Parse EAS-CAP out of CAP message. 
     * 3. Then validate that EAS-CAP message against an EAS-CAP schema to make sure that it is conformed 
     * to EAS-CAP format and that it has the minimum set of EAS-CAP required elements.
     * 4. Then make sure all EAS-CAP required elements are valid   
     *
     * @param  capFile          a CAP XML file
     * @param  capXsdUrl        a CAP Schema URL
     * @param  easCapXsdFile    a EAS-CAP Schema file
     * @return                  a result of whether Accepted, Rejected, or Ignored. Validation informations will be returned along with result in the format of "Rejected: ..."
     */
    public String validateEASCAPWithStrictCAPConformance(File capFile, URL capXsdUrl, File easCapXsdFile) throws Exception {
        return validate(readTextFile(capFile), readTextURL(capXsdUrl), readTextFile(easCapXsdFile));
    }

    /**
     * 1. Take a CAP message. Validate it against a CAP 1.1 schema to make sure that it is conformed 
     * to CAP 1.1 format and that it has the minimum set of CAP 1.1 required elements.
     * 2. Parse EAS-CAP out of CAP message. 
     * 3. Then validate that EAS-CAP message against an EAS-CAP schema to make sure that it is conformed 
     * to EAS-CAP format and that it has the minimum set of EAS-CAP required elements.
     * 4. Then make sure all EAS-CAP required elements are valid   
     *
     * @param  capFile          a CAP XML file
     * @param  capXsdUrl        a CAP Schema URL
     * @param  easCapXsdUrl     a EAS-CAP Schema URL
     * @return                  a result of whether Accepted, Rejected, or Ignored. Validation informations will be returned along with result in the format of "Rejected: ..."
     */
    public String validateEASCAPWithStrictCAPConformance(File capFile, URL capXsdUrl, URL easCapXsdUrl) throws Exception {
        return validate(readTextFile(capFile), readTextURL(capXsdUrl), readTextURL(easCapXsdUrl));
    }

    /**
     * Get the validation result after each validation process (Accepted, Ignored, Rejected)
     * @return        the validating result
     */
    public String getResultState() {
        return resultState;
    }

    /**
     * Take a CAP message, CAP schema and EAS-CAP schema as parameters.
     * Then base upon the availabilty of the above parameters, choose to validate the CAP message 
     * against EAS-CAP schema only or validate that CAP message with strict CAP 1.1 conformance    
     *
     * @param  cap              a CAP XML String
     * @param  capXsd           a CAP Schema String
     * @param  easCapXsd        a EAS-CAP Schema String
     * @return                  result of whether Accepted, Rejected, or Ignored. Validation informations will be returned along with result in the format of "Rejected: ..."
     */
    protected String validate(String cap, String capXsd, String easCapXsd) throws Exception {
        String result = "";

        resultState = null;

        if (capXsd == null && easCapXsd != null) {                  //Validate to EAS-CAP only and without strict adherence to CAP 1.1 
            result = validateEASCAPImplementation(cap, easCapXsd);
        } else if (capXsd != null && easCapXsd != null) {           //Validate to EAS-CAP  with strict adherence to CAP 1.1 
            result = validateSchema(cap, capXsd);                   //Validate againts CAP 1.1 Schema first
            if (result.equalsIgnoreCase(VALID)) {                   //Validate againts EASCAP Schema second
                result = validateEASCAPImplementation(cap, easCapXsd);
            } else {
                resultState = "Rejected";
                result = resultState + ": " + result;
            }
        }

        return result;
    }

    /**
     * Validate an XML message against an XML schema 
     *
     * @param  cap              a CAP XML String
     * @param  xsd              a CAP Schema String
     * @return                  result of whether Valid or reason for failure.
     */
    protected String validateSchema(String cap, String xsd) throws Exception {
        SchemaFactory factory = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema");
        StringReader xsdString = new StringReader(xsd);
        Schema schema = factory.newSchema(new StreamSource(xsdString));
        Validator validator = schema.newValidator();
        StringReader capString = new StringReader(cap);

        try {
            validator.validate(new StreamSource(capString));
            return VALID;
        } catch (SAXException ex) {
            return ex.getMessage();
        }
    }
//    protected String validateSchema(String cap, String xsd) throws Exception {
//        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
//        StringReader xsdString = new StringReader(xsd);
//        SchemaFactory sfactory = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema");
//        Schema schema = sfactory.newSchema(new StreamSource(xsdString));
//        factory.setSchema(schema);
//
//        Document doc = null;
//        //StringReader capString = new StringReader(cap);
//        InputStream in = new ByteArrayInputStream(cap.getBytes("UTF-8"));
//        try {
//            DocumentBuilder parser = factory.newDocumentBuilder();
//            doc = parser.parse(in);
//            return VALID;
//        } catch (SAXException ex) {
//            return ex.getMessage();
//        }
//    }
    /**
     * 1. Take a CAP message. Parse EAS-CAP out of it. 
     * 2. Then validate that EAS-CAP message against an EAS-CAP schema to make sure that it is conformed 
     * to EAS-CAP format and that it has the minimum set of EAS-CAP required elements.
     * 3. Then make sure all EAS-CAP required elements are valid   
     *
     * @param  cap              a CAP XML String
     * @param  xsd              a CAP Schema String
     * @return                  a result of whether Accepted, Rejected, or Ignored. Validation informations will be returned along with result in the format of "Rejected: ..."                       
     */
    protected String validateEASCAPImplementation(String cap, String eascapxsd) throws Exception {
        String result = null;
        String eascap = parseEASCAPOutOfCAP(cap);
        result = validateSchema(eascap, eascapxsd);
        if (result.equalsIgnoreCase(VALID)) {
            result = isAllRequiredEASCAPElementsValid();
            if (!result.equalsIgnoreCase(VALID)) {
                resultState = "Rejected";
                result = resultState + ": " + result;
            }
        } else {

            if (result.contains(_xmlns + "alert") || result.contains(_xmlns + "identifier") || result.contains(_xmlns + "sender") ||
                    result.contains(_xmlns + "sent") || result.contains(_xmlns + "status") || result.contains(_xmlns + "msgType") ||
                    result.contains(_xmlns + "scope") || result.contains(_xmlns + "areaDesc") || result.contains(_xmlns + "uri")) {
                resultState = "Rejected";
            } else {
                resultState = "Ignored";
            }
            result = resultState + ": " + result;
        }

        if (result.equalsIgnoreCase(VALID)) {
            resultState = "Accepted";
            result = resultState + ": " + result;
        }

        return result;
    }

    /**
     * Make sure all EAS-CAP required elements are valid 
     *
     * @return                  result of whether valid or reasons for failure
     */
    protected String isAllRequiredEASCAPElementsValid() throws Exception {
        String result = null;

        result = validateEASCAPParameters();
        if (result.equalsIgnoreCase(VALID)) {
            result = validateEASCAPGeoCode();
            if (result.equalsIgnoreCase(VALID)) {
                result = validateEASCAPEventCode();
            }
        }
        return result;
    }

    /**
     * 1. If a <parameter> with <valueName> of "EAS-ORG" is present then its <value> should be either EAS, CIV, WXR, or PEP
     * 2. If a <parameter> with <valueName> of "EAS-STN-ID" is present then its <value> should be a string of 8 printable characters
     * 3. If a <parameter> with <valueName> of "EAS-Must-Carry" is present then its <value> should be either TRUE or FALSE     
     *
     * @return                  result of whether valid or reasons for failure
     */
    protected String validateEASCAPParameters() {
        String result = "";
        _easCapInfo.resetParameters();
        while (_easCapInfo.hasNextParameter()) {
            ValuePair vp = _easCapInfo.getNextParameterValuePair();
            String parameterValueName = vp.getValueName();
            String parameterValue = vp.getValue();
            if (parameterValueName.equals("EAS-ORG")) {
                if (!parameterValue.equals("EAS") && !parameterValue.equals("CIV") && !parameterValue.equals("WXR") && !parameterValue.equals("PEP")) {
                    result = result + "Parameter EAS-ORG must have a value of either EAS, CIV, WXR, or PEP only.\n";
                }
            } else if (parameterValueName.equals("EAS-STN-ID")) {
                if (!Pattern.compile("[^\\s-+]{8}").matcher(parameterValue).matches()) {
                    result = result + "Parameter EAS-STN-ID must have at least 8 printable characters without - or +.\n";
                }
            } else if (parameterValueName.equals("EAS-Must-Carry")) {
                if (!parameterValue.equalsIgnoreCase("TRUE") && !parameterValue.equalsIgnoreCase("FALSE")) {
                    result = result + "Parameter EAS-Must-Carry must have a value of either TRUE or FALSE only.\n";
                }
            }
        }

        if (result.equalsIgnoreCase("")) {
            return VALID;
        }

        return result;
    }

    /**
     * Make sure EAS-CAP <eventCode> field has the <valueName> as SAME and a <value> matching 3 letters EAS EEE event code
     *
     * @return                  result of whether valid or reasons for failure
     */
    protected String validateEASCAPEventCode() {
        _easCapInfo.resetEventCodes();
        while (_easCapInfo.hasNextEventCode()) {
            ValuePair vp = _easCapInfo.getNextEventCodeValuePair();
            String eventCodeValue = vp.getValue();
            String eventCodeValueName = vp.getValueName();
            if (eventCodeValueName.equals("SAME") && isEventCodeValid(eventCodeValue)) {
                return VALID;
            }
        }
        return "At least one <eventCode> with valueName of SAME and a value matching 3 letters EAS EEE event code is required";
    }
    
    /**
     * Make sure a event code string is matching 3 letters EAS EEE known event code
     *
     * @return                  true/false
     */
    protected boolean isEventCodeValid(String eventCode) {
        if (eventCode.equals("EAN") || eventCode.equals("EAT") || eventCode.equals("NIC") || eventCode.equals("NPT") ||
                eventCode.equals("RMT") || eventCode.equals("RWT") || eventCode.equals("ADR") || eventCode.equals("AVW") ||
                eventCode.equals("AVA") || eventCode.equals("BZW") || eventCode.equals("CAE") || eventCode.equals("CDW") ||
                eventCode.equals("CEM") || eventCode.equals("CFW") || eventCode.equals("CFA") || eventCode.equals("DSW") ||
                eventCode.equals("EQW") || eventCode.equals("EVI") || eventCode.equals("FRW") || eventCode.equals("FFW") ||
                eventCode.equals("FFA") || eventCode.equals("FFS") || eventCode.equals("FLW") || eventCode.equals("FLA") ||
                eventCode.equals("FLS") || eventCode.equals("HMW") || eventCode.equals("HWW") || eventCode.equals("HWA") ||
                eventCode.equals("HUW") || eventCode.equals("HUA") || eventCode.equals("HLS") || eventCode.equals("LEW") ||
                eventCode.equals("LAE") || eventCode.equals("NMN") || eventCode.equals("TOE") || eventCode.equals("NUW") ||
                eventCode.equals("DMO") || eventCode.equals("RHW") || eventCode.equals("SVR") || eventCode.equals("SVA") ||
                eventCode.equals("SVS") || eventCode.equals("SPW") || eventCode.equals("SMW") || eventCode.equals("SPS") ||
                eventCode.equals("TOR") || eventCode.equals("TOA") || eventCode.equals("TRW") || eventCode.equals("TRA") ||
                eventCode.equals("TSW") || eventCode.equals("TSA") || eventCode.equals("VOW") || eventCode.equals("WSW") ||
                eventCode.equals("WSA")) {
            return true;
        }

        return false;
    }

    
    /**
     * Make sure at least one EAS-CAP <geocode> with <valueName> of "SAME" 
     * and its <value> string representing the 6 digits EAS location.
     *
     * @return                  result of whether valid or reasons for failure
     */
    protected String validateEASCAPGeoCode() {

        _easCapArea.resetGeocodes();
        while (_easCapArea.hasNextGeocode()) {
            ValuePair vp = _easCapArea.getNextGeocodeValuePair();
            String geocodeValue = vp.getValue();
            String geocodeValueName = vp.getValueName();
            if (geocodeValueName.equals("SAME") && geocodeValue.matches("\\d{6}")) {
                return VALID;
            }
        }
        return "At least one <geocode> with <valueName> of SAME and one <value> string representing the 6 digits EAS Location must be defined.";
    }

    /**
     * Take a CAP message and convert it to EAS-CAP by extracting only EAS-CAP relevant fields
     * 
     * @param  cap         a cap message
     * @return             an EAS-CAP message
     */
    protected String parseEASCAPOutOfCAP(String cap) {
        _easCapAlert = EasCapAlert.parse(EasCapAlert.parse(cap).toEASCAP());

        if (_easCapAlert != null) {
            _easCapAlert.resetInfos();
            if (_easCapAlert.hasNextInfo()) {
                _easCapInfo = _easCapAlert.getNextInfo();
            }
        }

        if (_easCapInfo != null) {
            _easCapInfo.resetAreas();
            if (_easCapInfo.hasNextArea()) {
                _easCapArea = _easCapInfo.getNextArea();
            }
        }

        return _easCapAlert.toEASCAP();
    }

    /**
     * Read text from a URL
     * 
     * @param  url         URL class
     * @return             text from URL
     */
    protected String readTextURL(URL url) throws Exception {
        return readText(new BufferedReader(new InputStreamReader(url.openStream())));
    }

    /**
     * Read text from a file that locates in a jar file 
     * 
     * @param  fileName         name of file
     * @return                  text from file
     */
    protected String readTextFileFromJar(String fileName) throws Exception {
        return readText(new BufferedReader(new InputStreamReader(getClass().getResourceAsStream(fileName))));
    }

    /**
     * Read text from a file
     * 
     * @param  file          File class
     * @return               text from file
     */
    protected String readTextFile(File file) throws Exception {
        return readText(new BufferedReader(new FileReader(file)));
    }

    /**
     * Read text from a BufferedReader
     * 
     * @param  br          BufferedReader class
     * @return             text from BufferedReader
     */
    protected String readText(BufferedReader br) throws Exception {
        String line = null;
        StringBuilder result = new StringBuilder();
        try {
            while ((line = br.readLine()) != null) {
                result.append(line + System.getProperty("line.separator"));
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        } finally {
            br.close();
        }

        return result.toString();
    }

    public static void main(String[] args) {
        try {
            EasCapValidator cev = new EasCapValidator();
            System.out.println(cev.validateEASCAP(cev.readTextFile(new File("C:\\Documents and Settings\\Thai\\Desktop\\cap9.xml"))));
            System.out.println(cev.validateEASCAPWithStrictCAPConformance(cev.readTextFile(new File("C:\\Documents and Settings\\Thai\\Desktop\\cap9.xml"))));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
